#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include "canfd_test.h"
#include "canfd_rw.h"
#include "canfd_config.h"
#include "unit_test.h"
#include "thread_ctrl.h"

static struct unit_item_t unit_item[CANFD_ITEM_NUM];
static struct thread_param_t thread_param[CANFD_MAX_CHANNEL * 2];
static struct thread_info_t thread_info = {
    .num = CANFD_MAX_CHANNEL * 2,
    .param = thread_param,
};
static struct canfd_dev_t canfd_dev[CANFD_MAX_CHANNEL];
static struct canfd_param_t canfd_param = {
    .dev = canfd_dev,
};
static struct canfd_item_t canfd_item = {
    .param = &canfd_param,
    .thread = &thread_info,
};

static void init_unit_item(struct unit_item_t *item) {
    item[0] = (struct unit_item_t){0,  "null",   "0. 退出程序",        NULL};
    item[1] = (struct unit_item_t){1,  "level",  "1. 电平质量测试",    config_canfd_level_quality};
}

static int get_param(struct canfd_param_t *param) {
    struct canfd_item_t *pcanfd_item = (struct canfd_item_t *)param->parent;
    struct thread_info_t *pthread_info = pcanfd_item->thread;
    struct thread_param_t *pthread = pthread_info->param;
    int ret = 0;
    char input[32];
    uint8_t i = 0;

    printf("\n===== %s 设备测试程序 =====\n", CANFD_ITEM_NAME);
    printf("请选择测试项:\n");
    for (int i = 0; i < CANFD_ITEM_NUM; i++) {
        printf("%s\n", unit_item[i].text);
    }
    printf("请输入选择 (输入数字): ");
    if (fgets(input, sizeof(input), stdin) == NULL) {
        return -1;
    }
    if (pthread->exit_sig) {
        param->item_id = 0;
        return 0;
    }
    param->item_id = atoi(input);
    if (param->item_id == 0)
        return 0;
    if (unit_item[param->item_id].config != NULL) {
        unit_item[param->item_id].config(param);
    }

    printf("请输入%s通道号 (0-%d): ", CANFD_ITEM_NAME, param->max_num - 1);
    if (fgets(input, sizeof(input), stdin) == NULL) {
        return -1;
    }
    if (pthread->exit_sig) {
        param->item_id = 0;
        return 0;
    }
    param->dev_id = atoi(input);
    if (param->dev_id >= param->max_num) {
        param->dev_id = 0;
        for (i = 0; i < param->max_num; i++) {
            param->dev[i].index = i;
        }
    } else {
        param->dev_num = 1;
        param->dev[param->dev_id].index = param->dev_id;
    }

    printf("请输入发送报文个数(%d): ", param->write_cnt);
    if (fgets(input, sizeof(input), stdin) == NULL) {
        return -1;
    }
    if (pthread->exit_sig) {
        param->item_id = 0;
        return 0;
    }
    if (input[0] == '\n') {
        param->write_cnt = param->write_cnt;
    } else {
        param->write_cnt = atoi(input);
    }
    printf("param->write_cnt=%d\n", param->write_cnt);

    printf("是否使能报文间暂停 (y/n): ");
    if (fgets(input, sizeof(input), stdin) == NULL) {
        return -1;
    }
    if (pthread->exit_sig) {
        param->item_id = 0;
        return 0;
    }
    /* 移除换行符 (如果存在) */
    input[strcspn(input, "\n")] = '\0';
    /* 不区分大小写比较字符 */
    if (strcasecmp(input, "y") == 0 || strcasecmp(input, "yes") == 0) {
        param->en_pause = 1;
    } else {
        param->en_pause = 0;
    }
    printf("param->en_pause=%d\n", param->en_pause);

    return ret;
}

static unsigned int parse_arg_dec_or_hex(const char *arg) {
    unsigned int value = 0;
    if (strncmp(arg, "0x", 2) == 0) {
        /* If the input starts with "0x", treat it as a hexadecimal number */
        value = (unsigned int)strtoul(arg + 2, NULL, 16);
    } else {
        /* Otherwise, treat it as a decimal number */
        value = (unsigned int)atoi(arg);
    }
    return value;
}

static int usage(int argc, char *argv[])
{
    uint8_t index = 0;
    uint8_t i = 0;
    char *str = NULL;

    if (argc < 5) {
        printf("用法: %s <模块设备号> <测试项编号> <rw> <Mbps> <通道数量> <通道号>... <发送帧数> <帧ID> <帧间隔ms>\n", argv[0]);
        printf("示例: %s 1 1 1 0 100 0x01\n", argv[0]);
        return EXIT_FAILURE;
    } else {
        index = CANFD_ARGV_OFFSET;
        canfd_param.item_id = atoi(argv[index++]);
        if (canfd_param.item_id >= CANFD_ITEM_NUM) {
            fprintf(stderr, "dev test item=%d, max is %d\n", canfd_param.item_id, CANFD_ITEM_NUM - 1);
        } else {
            if (unit_item[canfd_param.item_id].config != NULL) {
                unit_item[canfd_param.item_id].config(&canfd_param);
            }
            /* rw */
            str = argv[index++];
            if (strcmp(str, "r") == 0) {
                canfd_param.en_read = 1;
                canfd_param.en_write = 0;
            } else if (strcmp(str, "w") == 0) {
                canfd_param.en_read = 0;
                canfd_param.en_write = 1;
            } else if (strcmp(str, "rw") == 0) {
                canfd_param.en_read = 1;
                canfd_param.en_write = 1;
            } else {
                return EXIT_FAILURE;
            }
            printf("Set %s en_read=%d en_write=%d\n", canfd_param.name, canfd_param.en_read, canfd_param.en_write);
            /* Mbps */
            canfd_param.baud_id = atoi(argv[index++]);
            switch (canfd_param.baud_id) {
            case 1:
                canfd_param.baud_id = 1;
                break;
            case 2:
                canfd_param.baud_id = 2;
                break;
            case 4:
                canfd_param.baud_id = 3;
                break;
            case 5:
                canfd_param.baud_id = 4;
                break;
            default:
                return EXIT_FAILURE;
                break;
            }
            printf("Set %s baud_id=%d\n", canfd_param.name, canfd_param.baud_id);
            /* 通道数量 */
            canfd_param.dev_num = atoi(argv[index++]);
            if (canfd_param.dev_num > CANFD_MAX_CHANNEL) {
                fprintf(stderr, "dev channel number=%d, max is %d\n", canfd_param.dev_num, CANFD_MAX_CHANNEL);
            } else {
                printf("dev channel number=%d\n", canfd_param.dev_num);
                for (i = 0; i < canfd_param.dev_num; i++) {
                    canfd_param.dev[i].index = atoi(argv[index++]);
                    if (canfd_param.dev[i].index >= CANFD_MAX_CHANNEL) {
                        fprintf(stderr, "dev channel=%d, max is %d\n", canfd_param.dev[i].index, CANFD_MAX_CHANNEL - 1);
                    } else {
                        printf("dev channel=%d\n", canfd_param.dev[i].index);
                    }
                }
                /* 发送帧数 */
                if (index < argc) {
                    canfd_param.read_cnt = -1;
                    canfd_param.write_cnt = atoi(argv[index++]);
                    printf("dev read_cnt=%d\n", canfd_param.read_cnt);
                    printf("dev write_cnt=%d\n", canfd_param.write_cnt);
                } else {
                    fprintf(stderr, "argc=%d index=%d\n", argc, index);
                }
                /* 帧 ID */
                canfd_param.xcan_id = parse_arg_dec_or_hex(argv[index++]);
                for (i = 0; i < canfd_param.dev_num; i++) {
                    canfd_param.dev[i].msg[0].id = canfd_param.xcan_id;
                    printf("Set %s%d msg.id=0x%08x\n", canfd_param.name, i, canfd_param.xcan_id);
                }
                /* 帧 ID */
                canfd_param.delay_ms = parse_arg_dec_or_hex(argv[index++]);
                printf("Set %s delay_ms=%d\n", canfd_param.name, canfd_param.delay_ms);
            }
        }
        return EXIT_SUCCESS;
    }
}

int canfd_test(int argc, char *argv[])
{
    struct thread_param_t *pthread = &thread_param[0];
    struct canfd_param_t *pparam = &canfd_param;
    struct canfd_dev_t *pdev = &pparam->dev[0];
    int ret = 0;
    uint8_t i = 0;
    uint8_t thread_cnt = 0;
    // char path[PATH_MAX] = {0};
    pthread_t sig_tid;

    canfd_item.thread = &thread_info;
    canfd_item.thread->param = &thread_param[0];
    canfd_item.param = &canfd_param;
    canfd_item.param->dev_num = CANFD_MAX_CHANNEL;
    canfd_item.param->dev = &canfd_dev[0];
    canfd_param.parent = (void *)&canfd_item;
    for (i = 0; i < CANFD_MAX_CHANNEL; i++) {
        canfd_dev[i].parent = (void *)canfd_item.param;
    }

    init_process_signal_handle(&sig_tid, signal_handler_thread, canfd_item.thread);
    init_unit_item(unit_item);

    if (argc > CANFD_ARGV_OFFSET) {
        pparam->type = atoi(argv[CANFD_ARGV_OFFSET - 1]);
        if (pparam->type > IET_TYPE_NUM) {
            return EXIT_FAILURE;
        }
    } else {
        while (!pthread->exit_sig) {
            if (get_module_type(&pparam->type) < 0) {
                printf("无效选择，请重新输入\n");
                sleep(2);
                continue;
            } else {
                break;
            }
        }
    }
    pparam->dev_num = get_dev_num(CANFD_DRV_NAME);
    pparam->max_num = pparam->dev_num;
    snprintf(pparam->name, sizeof(pparam->name), "%s", CANFD_DRV_NAME);
    printf("Get %s device number %d\n", CANFD_DRV_NAME, pparam->dev_num);
    while (!pthread->exit_sig) {
        thread_cnt = 0;
        // canfd_param.dev_num = CANFD_MAX_CHANNEL;

        if (argc > CANFD_ARGV_OFFSET) {
            if (EXIT_SUCCESS != usage(argc, argv)) {
                return EXIT_FAILURE;
            }
        } else {
            if (0 != get_param(pparam)) {
                printf("无效选择，请重新输入\n");
                continue;
            }
            if (0 == pparam->item_id) {
                printf("程序退出\n");
                break;
            }
        }

        if (unit_item[pparam->item_id].config != NULL) {
            printf("\n测试项 %d 正在执行\n", pparam->item_id);
            for (i = pparam->dev_id; i < (pparam->dev_id + pparam->dev_num); i++) {
                pdev = &pparam->dev[i];
                ret = open_canfd(pparam, CANFD_DRV_NAME, pdev, i);
                if (ret < 0)
                    return ret;
                ret = set_canfd_baud_rate(pdev->fd, &pdev->arbitration_baud[0], 
                                          &pdev->data_baud_rate[0]);
                if (ret < 0)
                    return ret;
                ret = start_canfd(pdev->fd);
                if (ret < 0)
                    return ret;

                if (pparam->en_read == 1) {
                    pdev->read_thread = &pthread[thread_cnt];
                    snprintf(pthread[thread_cnt].name, sizeof(pthread[thread_cnt].name), 
                             "%s%s%d", "recv_", pparam->name, pdev->index);
                    if (pthread_create(&pthread[thread_cnt].id, NULL, recv_canfd_thread, pdev) != 0) {
                        fprintf(stderr, "Create %s receive thread failed\n", pdev->path);
                    } else {
                        printf("Create %s receive thread success\n", pdev->path);
                    }
                    thread_cnt++;
                    usleep(5000);
                }

                if (pparam->en_write == 1) {
                    pdev->write_thread = &pthread[thread_cnt];
                    snprintf(pthread[thread_cnt].name, sizeof(pthread[thread_cnt].name), 
                             "%s%s%d", "send_", pparam->name, pdev->index);
                    if (pthread_create(&pthread[thread_cnt].id, NULL, send_canfd_thread, pdev) != 0) {
                        fprintf(stderr, "Create %s send thread failed\n", pdev->path);
                    } else {
                        printf("Create %s send thread success\n", pdev->path);
                    }
                    thread_cnt++;
                    usleep(5000);
                }
            }

            for (i = 0; i < thread_cnt && !pthread->exit_sig; i++) {
                pthread_join(pthread[i].id, NULL);
            }

            if (pthread->exit_sig) {
                printf("测试项 %d 用户取消\n", pparam->item_id);
                sleep(2);
            } else {
                printf("测试项 %d 执行完成\n", pparam->item_id);
                sleep(2);
            }
        } else {
            printf("测试项 %d 尚未实现\n", pparam->item_id);
            sleep(2);
        }

        thread_cnt = 0;
    }

    printf("%s return\n", __FUNCTION__);

    return ret;
}
